//
//  PMAssetEntity.m
//  similar_img
//
//  Created by osulcode.xiao on 2022/3/31.
//

#import "PMAssetEntity.h"

@implementation PMAssetEntity

- (instancetype)initWithId:(NSString *)id createDt:(long)createDt width:(NSUInteger)width height:(NSUInteger)height
duration:(long)duration type:(int)type {
    self = [super init];
    if (self) {
        self.id = id;
        self.createDt = createDt;
        self.width = width;
        self.height = height;
        self.duration = duration;
        self.type = type;
    }
    
    return self;
}

+ (instancetype)entityWithId:(NSString *)id createDt:(long)createDt width:(NSUInteger)width height:(NSUInteger)height
duration:(long)duration type:(int)type {
    return [[self alloc] initWithId:id createDt:createDt width:width height:height duration:duration type:type];
}

+ (PMAssetEntity *)convertPHAssetToAssetEntity:(PHAsset *)asset
                                     needTitle:(BOOL)needTitle {
    // type:
    // 0: all , 1: image, 2:video
    
    int type = 1;
//    if (asset.isImage) {
//        type = 1;
//    } else if (asset.isVideo) {
//        type = 2;
//    }
    
    NSDate *date = asset.creationDate;
    long createDt = (long) date.timeIntervalSince1970;
    
    NSDate *modifiedDate = asset.modificationDate;
    long modifiedTimeStamp = (long) modifiedDate.timeIntervalSince1970;
    
    PMAssetEntity *entity = [PMAssetEntity entityWithId:asset.localIdentifier
                                               createDt:createDt
                                                  width:asset.pixelWidth
                                                 height:asset.pixelHeight
                                               duration:(long) asset.duration
                                                   type:type];
    entity.phAsset = asset;
    entity.modifiedDt = modifiedTimeStamp;
    entity.lat = asset.location.coordinate.latitude;
    entity.lng = asset.location.coordinate.longitude;
    entity.title = needTitle ? [PMAssetEntity title: asset] : @"";
    entity.favorite = asset.isFavorite;
    entity.subtype = [PMAssetEntity unwrappedSubtype:asset];
    
    return entity;
}

+ (NSString *)title:(PHAsset *)asset {
    @try {
        NSString *result = [asset valueForKey:@"filename"];
        return result;
    } @catch (NSException *exception) {
        NSArray *array = [PHAssetResource assetResourcesForAsset:asset];
        for (PHAssetResource *resource in array) {
            return resource.originalFilename;
        }
        
        PHAssetResource *firstRes = array.firstObject;
        if (firstRes) {
            return firstRes.originalFilename;
        }
        
        return @"";
    }
}

+ (int)unwrappedSubtype:(PHAsset *)asset {
    PHAssetMediaSubtype subtype = [asset mediaSubtypes];
    if (subtype & PHAssetMediaSubtypePhotoPanorama) {
        return 1;
    }
    if (subtype & PHAssetMediaSubtypePhotoHDR) {
        return 2;
    }
    if (subtype & PHAssetMediaSubtypePhotoScreenshot) {
        return 4;
    }
    if (@available(iOS 9.1, *)) {
        if (subtype & PHAssetMediaSubtypePhotoLive) {
            return 8;
        }
    }
    if (@available(iOS 10.2, *)) {
        if (subtype & PHAssetMediaSubtypePhotoDepthEffect) {
            return 16;
        }
    }
    if (subtype & PHAssetMediaSubtypeVideoStreamed) {
        return 65536;
    }
    if (subtype & PHAssetMediaSubtypeVideoHighFrameRate) {
        return 131072;
    }
    if (subtype & PHAssetMediaSubtypeVideoTimelapse) {
        return 262144;
    }
    return 0;
}

+ (PMAssetEntity *)getAssetEntity:(NSString *)assetId {
    PHFetchResult<PHAsset *> *result =
    [PHAsset fetchAssetsWithLocalIdentifiers:@[assetId] options:nil];
    if (result == nil || result.count == 0) {
        return nil;
    }
    
    PHAsset *asset = result[0];
    PMAssetEntity * entity = [self convertPHAssetToAssetEntity:asset needTitle:NO];
    return entity;
}

+ (void)getThumbWithId:(NSString *)assetId option:(PMThumbLoadOption *)option block:(ImageBlock)block{
    PMAssetEntity *entity = [self getAssetEntity:assetId];
    if (entity && entity.phAsset) {
        PHAsset *asset = entity.phAsset;
        [self fetchThumb:asset option:option block:block];
    } else {
        block(nil);
    }
}

+ (void)fetchThumb:(PHAsset *)asset option:(PMThumbLoadOption *)option block:(ImageBlock)block{
    PHImageManager *manager = PHImageManager.defaultManager;
    PHImageRequestOptions *requestOptions = [PHImageRequestOptions new];
    requestOptions.deliveryMode = option.deliveryMode;
    requestOptions.resizeMode = option.resizeMode;
    
    [requestOptions setNetworkAccessAllowed:YES];
    
    int width = option.width;
    int height = option.height;
    
    [manager requestImageForAsset:asset
                       targetSize:CGSizeMake(width, height)
                      contentMode:option.contentMode
                          options:requestOptions
                    resultHandler:^(UIImage *result, NSDictionary *info) {
        NSData *imageData = [self convertToData:result formatType:option.format quality:option.quality];
        if (imageData) {
            id data = [FlutterStandardTypedData typedDataWithBytes:imageData];
//            [handler reply:data];
            block(data);
        } else {
//            [handler reply: nil];
            block(nil);
        }
    }];
}

+ (void)getOriginImageWithId:(NSString *)assetId block:(ImageBlock)block{
    PMAssetEntity *entity = [self getAssetEntity:assetId];
    if (entity && entity.phAsset) {
        PHAsset *asset = entity.phAsset;
        [self fetchOriginImageFile:asset block:block];
    }
    block(nil);
}

+ (NSString *)makeAssetOutputPath:(PHAsset *)asset isOrigin:(Boolean)isOrigin manager:(NSFileManager *)manager {
    NSString *homePath = NSTemporaryDirectory();
    NSMutableString *path = [NSMutableString stringWithString:homePath];
    NSString *modifiedDate = [NSString stringWithFormat:@"%f", asset.modificationDate.timeIntervalSince1970];
    NSString *filename = [NSString stringWithFormat:@"%@%@_%@", modifiedDate, isOrigin ? @"_o" : @"", [asset valueForKey:@"filename"]];
    NSString *typeDirPath = [asset mediaType] == PHAssetMediaTypeImage ? @".image" : @".video";
    NSString *dirPath = [NSString stringWithFormat:@"%@%@", homePath, typeDirPath];
    if (manager == nil) {
        manager = NSFileManager.defaultManager;
    }
    [manager createDirectoryAtPath:dirPath
       withIntermediateDirectories:true
                        attributes:@{}
                             error:nil];
    [path appendFormat:@"%@/%@", typeDirPath, filename];
    return path;
}

+ (void)fetchOriginImageFile:(PHAsset *)asset block:(ImageBlock)block {
    PHAssetResource *imageResource = [self getAdjustResource:asset];
    if (!imageResource) {
        block(nil);
        return;
    }
    NSFileManager *fileManager = NSFileManager.defaultManager;
    NSString *path = [self makeAssetOutputPath:asset isOrigin:YES manager:fileManager];
    if ([fileManager fileExistsAtPath:path]) {
        block(path);
        return;
    }
    
    PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new];
    [options setNetworkAccessAllowed:YES];
    
    PHAssetResourceManager *resourceManager = PHAssetResourceManager.defaultManager;
    NSURL *fileUrl = [NSURL fileURLWithPath:path];
    [resourceManager writeDataForAssetResource:imageResource
                                        toFile:fileUrl
                                       options:options
                             completionHandler:^(NSError *_Nullable error) {
        if (error) {
            NSLog(@"error = %@", error);
            block(nil);
        } else {
            block(path);
        }
    }];
}

+ (PHAssetResource *)getAdjustResource:(PHAsset *)asset {
    NSArray<PHAssetResource *> *resources = [PHAssetResource assetResourcesForAsset:asset];
    if (resources.count == 0) {
        return nil;
    }
    
    if (resources.count == 1) {
        return resources[0];
    }
    
    if (![self isAdjust:asset]) {
        for (PHAssetResource *res in resources) {
            if (asset.mediaType == PHAssetMediaTypeImage
                && res.type == PHAssetResourceTypePhoto) {
                return res;
            }
            
            if (asset.mediaType == PHAssetMediaTypeVideo
                && res.type == PHAssetResourceTypeVideo) {
                return res;
            }
        }
        
        return nil;
    }
    
    for (PHAssetResource *res in resources) {
        if (asset.mediaType == PHAssetMediaTypeImage &&
            res.type == PHAssetResourceTypeFullSizePhoto) {
            return res;
        }
        
        if (asset.mediaType == PHAssetMediaTypeVideo &&
            res.type == PHAssetResourceTypeFullSizeVideo) {
            return res;
        }
    }
    return nil;
}

+ (BOOL)isAdjust:(PHAsset *)asset {
    NSArray<PHAssetResource *> *resources =
    [PHAssetResource assetResourcesForAsset:asset];
    if (resources.count == 1) {
        return NO;
    }
    
    if (asset.mediaType == PHAssetMediaTypeImage) {
        return [self imageIsAdjust:resources];
    }
    if (asset.mediaType == PHAssetMediaTypeVideo) {
        return [self videoIsAdjust:resources];
    }
    
    return NO;
}

+ (BOOL)imageIsAdjust:(NSArray<PHAssetResource *> *)resources {
    for (PHAssetResource *res in resources) {
        if (res.type == PHAssetResourceTypeFullSizePhoto) {
            return YES;
        }
    }
    return NO;
}

+ (BOOL)videoIsAdjust:(NSArray<PHAssetResource *> *)resources {
    for (PHAssetResource *res in resources) {
        if (res.type == PHAssetResourceTypeFullSizeVideo) {
            return YES;
        }
    }
    return NO;
}

+ (NSData *)convertToData:(UIImage *)image formatType:(PMThumbFormatType)type quality:(float)quality {
    NSData *resultData;
    if (type == PMThumbFormatTypePNG) {
        resultData = UIImagePNGRepresentation(image);
    } else {
        resultData = UIImageJPEGRepresentation(image, quality);
    }
    
    return resultData;
}

+ (id)getFirstObjFromFetchResult:(PHFetchResult<id> *)fetchResult {
    if (fetchResult && fetchResult.count > 0) {
        return fetchResult.firstObject;
    }
    return nil;
}

+ (void)removeAssetWithId:(NSString *)assetId type:(int)type block:(ImageBlock)block {
    if (type == 1) {
        PHFetchResult<PHAssetCollection *> *fetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[assetId] options:nil];
        PHAssetCollection *collection = [self getFirstObjFromFetchResult:fetchResult];
        if (!collection) {
            block(@"NO");
            return;
        }
        if (![collection canPerformEditOperation:PHCollectionEditOperationDelete]) {
            block(@"YES");
            return;
        }
        NSError *error;
        [PHPhotoLibrary.sharedPhotoLibrary performChangesAndWait:^{
            [PHAssetCollectionChangeRequest deleteAssetCollections:@[collection]];
        }                                                  error:&error];
            
        if (error) {
            block(@"NO");
            return;
        }
            
        block(@"NO");
            
    } else if (type == 2) {
        PHFetchResult<PHCollectionList *> *fetchResult = [PHCollectionList fetchCollectionListsWithLocalIdentifiers:@[assetId] options:nil];
        PHCollectionList *collection = [self getFirstObjFromFetchResult:fetchResult];
        if (!collection) {
            block(@"NO");
            return;
        }
        if (![collection canPerformEditOperation:PHCollectionEditOperationDelete]) {
            block(@"YES");
            return;
        }
        NSError *error;
        [PHPhotoLibrary.sharedPhotoLibrary performChangesAndWait:^{
            [PHCollectionListChangeRequest deleteCollectionLists:@[collection]];
        }                                                  error:&error];
            
        if (error) {
            block(@"NO");
            return;
        }
            
        block(@"NO");
    } else {
        block(@"NO");
    }
}

@end
